using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Dokan;
using RemoteCode;
using RemoteCode.Attributes;
using RemoteCode.Remote;

namespace MirrorDrive.Operations
{
    public class ClientOperations : DokanOperations
    {
        private Nexum _nexum;
        private InitializedRemoteClass _remote;

        public ClientOperations(Nexum nexum)
        {
            _nexum = nexum;
            _remote = _nexum.GetInitializedClass("Operations");
        }

        private void Copy(DokanFileInfo src, DokanFileInfo dst)
        {
            dst.Context = src.Context;
            dst.DeleteOnClose = src.DeleteOnClose;
            dst.InfoId = src.InfoId;
            dst.IsDirectory = src.IsDirectory;
            dst.Nocache = src.Nocache;
            dst.PagingIo = src.PagingIo;
            dst.ProcessId = src.ProcessId;
            dst.SynchronousIo = src.SynchronousIo;
            dst.WriteToEndOfFile = src.WriteToEndOfFile;
        }

        public int CreateFile(string filename, FileAccess access, FileShare share, FileMode mode, FileOptions options, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("CreateFile", filename, access, share, mode, options, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;
        }

        public int OpenDirectory(string filename, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("OpenDirectory", filename, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;     
        }

        public int CreateDirectory(string filename, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("CreateDirectory", filename, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;
        }

        public int Cleanup(string filename, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("Cleanup", filename, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;        
        }

        public int CloseFile(string filename, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("CloseFile", filename, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;                         
        }

        public int ReadFile(string filename, ref byte[] buffer, ref uint readBytes, long offset, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("ReadFile", filename, buffer, offset, info);
            Copy(ret.DokanFileInfo, info);
            buffer = (byte[])ret.RetObjects[0];
            readBytes = (uint)ret.RetObjects[1];
            return ret.RetValue; 
        }

        public int WriteFile(string filename, byte[] buffer, ref uint writtenBytes, long offset, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("WriteFile", filename, buffer, offset, info);
            Copy(ret.DokanFileInfo, info);
            writtenBytes = (uint)ret.RetObjects[0];
            return ret.RetValue; 
        }

        public int FlushFileBuffers(string filename, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("FlushFileBuffers", filename, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;            
        }

        public int GetFileInformation(string filename, ref FileInformation fileinfo, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("GetFileInformation", filename, info);
            Copy(ret.DokanFileInfo, info);
            fileinfo = (FileInformation)ret.RetObjects[0];
            return ret.RetValue;  
        }

        public int FindFiles(string filename, ref ArrayList files, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("FindFiles", filename, info);
            Copy(ret.DokanFileInfo, info);
            files = (ArrayList)ret.RetObjects[0];
            return ret.RetValue; 
        }

        public int SetFileAttributes(string filename, FileAttributes attr, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("SetFileAttributes", filename, attr, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;            
        }

        public int SetFileTime(string filename, DateTime ctime, DateTime atime, DateTime mtime, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("SetFileTime", filename, ctime, atime, mtime, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;                
        }

        public int DeleteFile(string filename, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("DeleteFile", filename, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;              
        }

        public int DeleteDirectory(string filename, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("DeleteDirectory", filename, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;       
        }

        public int MoveFile(string filename, string newname, bool replace, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("MoveFile", filename, newname, replace, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;                
        }

        public int SetEndOfFile(string filename, long length, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("SetEndOfFile", filename, length, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;             
        }

        public int SetAllocationSize(string filename, long length, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("SetAllocationSize", filename, length, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;             
        }

        public int LockFile(string filename, long offset, long length, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("LockFile", filename, offset, length, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;            
        }

        public int UnlockFile(string filename, long offset, long length, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("UnlockFile", filename, offset, length, info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;                 
        }

        public int GetDiskFreeSpace(ref ulong freeBytesAvailable, ref ulong totalBytes, ref ulong totalFreeBytes, DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("GetDiskFreeSpace", info);
            Copy(ret.DokanFileInfo, info);
            freeBytesAvailable = (ulong)ret.RetObjects[0];
            totalBytes = (ulong)ret.RetObjects[1];
            totalFreeBytes = (ulong)ret.RetObjects[2];
            return ret.RetValue;    
        }

        public int Unmount(DokanFileInfo info)
        {
            ReturnObject ret = _remote.InvokeMethod<ReturnObject>("Unmount", info);
            Copy(ret.DokanFileInfo, info);
            return ret.RetValue;   
        }
    }
}